﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace CoolCode
{
    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public class AttachDataAttribute : Attribute
    {
        public AttachDataAttribute(object key, object value)
        {
            this.Key = key;
            this.Value = value;
        }

        public object Key { get; private set; }

        public object Value { get; private set; }
    }

    public static class AttachDataExtensions
    {
        private static Dictionary<string, object> _cacheAttachedData = new Dictionary<string, object>();

        public static object GetAttachedData(
            this ICustomAttributeProvider provider, object key)
        {
            var attributes = (AttachDataAttribute[])provider.GetCustomAttributes(
                typeof(AttachDataAttribute), false);
            return attributes.First(a => a.Key.Equals(key)).Value;
        }

        public static T GetAttachedData<T>(
            this ICustomAttributeProvider provider, object key)
        {
            return (T)provider.GetAttachedData(key);
        }

        public static object GetAttachedData(this Enum en, object key)
        {
            object value;
            string enumFullName = getEnumFullName(en, key);
            if (!_cacheAttachedData.TryGetValue(enumFullName, out value))
            {
                value = en.GetType().GetField(en.ToString()).GetAttachedData(key);
                _cacheAttachedData.Add(enumFullName, value);
            }
            return value;
        }

        public static T GetAttachedData<T>(this Enum en, object key)
        {
            return (T)en.GetAttachedData(key);
        }

        private static string getEnumFullName(Enum en, object key)
        {
            return en.GetFullName() + "." + key;
        }
    }

    /*Sample:
public enum AgeRange
{ 
    [AttachData(AgeRangeAttachData.Text, "18岁及以下")]
    LessThan18,

    [AttachData(AgeRangeAttachData.Text, "19至29岁")]
    From19To29,

    [AttachData(AgeRangeAttachData.Text, "30岁及以上")]
    Above29
}

public enum AgeRangeAttachData
{ 
    Text
}

public static class AgeRangeExtensions
{
    public static string GetText(this AgeRange range)
    {
        return range.GetAttachedData<string>(AgeRangeAttachData.Text);
    }
}

     */

    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
    public class AttachStringAttribute : Attribute
    {
        public string Value { get; private set; }

        public AttachStringAttribute(string value)
        {
            this.Value = value;
        }
    }

    public static class AttachStringExtensions
    {
        private static Dictionary<string, string> _cacheAttachedData = new Dictionary<string, string>();

        /// <summary>
        /// 获取Enum中标记[AttachString]的字符串
        /// </summary>
        /// <param name="en"></param>
        /// <returns></returns>
        public static string GetAttachedString(this Enum en)
        {
            string value;
            string enumFullName = en.GetFullName();
            if (!_cacheAttachedData.TryGetValue(enumFullName, out value))
            {
                value = getAttachedStringHelper(en);
                _cacheAttachedData.Add(enumFullName, value);
            }
            return value;
        }

        public static string GetAttachedString(this ICustomAttributeProvider provider)
        {
            var attributes = (AttachStringAttribute[])provider.GetCustomAttributes(
                typeof(AttachStringAttribute), false);
            if (attributes == null || attributes.Length == 0)
                throw new NotSupportedException("e.g. [AttachString(\"foo\")]");
            return attributes.First().Value;
        }

        private static string getAttachedStringHelper(this Enum value)
        {
            return value.GetType().GetField(value.ToString()).GetAttachedString();
        }


    }

    static class EnumHelper
    {
        public static string GetFullName(this Enum en)
        {
            return en.GetType().FullName + "." + en.ToString();
        }
    }

    public class Enum<T>
    {
        public static void Foreach(Action<T> action)
        {
            Array values = Enum.GetValues(typeof(T));
            foreach (var value in values)
            {
                action((T)value);
            }
        }

        public static T Find(Func<T, bool> func)
        {
            Array values = Enum.GetValues(typeof(T));
            foreach (var value in values)
            {
                T t = (T)value;
                if (func(t))
                    return t;
            }
            return default(T);
        }

        public static List<T> ToList()
        {
            Array values = Enum.GetValues(typeof(T));
            List<T> list = new List<T>(values.Length);
            foreach (var value in values)
            {
                list.Add((T)value);
            }
            return list;
        }

        public static IEnumerable<T> AsEnumerable()
        {
            //Array values = Enum.GetValues(typeof(T));
            EnumQuery<T> query =new EnumQuery<T>();
            return query;
        }

        public static IEnumerable<TResult> Select<TResult>(Func<T, TResult> selector)
        {
           return   ToList().Select(selector);
        }

        public static IEnumerable<T> Where(Func<T, bool> predicate)
        {
            return AsEnumerable().Where(predicate);
        }
    }

    public  class EnumQuery<T>:IEnumerable<T> 
    {
        private List<T> list;
        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            Array values = Enum.GetValues(typeof(T));
            list  = new List<T>(values.Length);
            foreach (var value in values)
            {
                list.Add((T)value);
            }
            return list.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

       
    }
}
